﻿namespace DataDuctus.MongoDb.Serialization.Extensions
{
	using System;
	using System.Collections.Generic;
	using System.ComponentModel;
	using System.Diagnostics;
	using System.Reflection;

	using MongoDB.Bson;
	using MongoDB.Bson.Serialization;
	using MongoDB.Bson.Serialization.IdGenerators;

	internal static class BsonExtensions
	{
		#region AddKnownType
		internal static void AddKnownType<T>(this BsonClassMap<T> cm, Type type)
		{
			var types = (List<Type>)cm.KnownTypes;
			types.Add(type);
		}
		#endregion // AddKnownType

		#region IdGenerator
		internal static IIdGenerator GetIdGenerator(this MemberInfo member)
		{
			var type = member.ExtractType();

			if (type.Equals(typeof(string)))
			{
				return StringObjectIdGenerator.Instance;
			}

			if (type.Equals(typeof(BsonObjectId)))
			{
				return BsonObjectIdGenerator.Instance;
			}

			if (type.Equals(typeof(Guid)))
			{
				return GuidGenerator.Instance;
			}

			if (type.Equals(typeof(ObjectId)))
			{
				return ObjectIdGenerator.Instance;
			}

			throw new Exception(
				string.Format(
					"Cannot handle id generator for Id member = {0} on type = {1}", member.Name, member.DeclaringType.FullName));
		}
		#endregion // IdGenerator

		#region TypeConverter Mapping
		internal static BsonType TypeConverterToBsonRepresentation(this MemberInfo member)
		{
			var typeConverter = member.GetAttribute<TypeConverterAttribute>();

			if (null == typeConverter)
			{
				return BsonType.EndOfDocument;
			}

			var type = Type.GetType(typeConverter.ConverterTypeName);

			if (null == type)
			{
				Trace.TraceError("Could not get typeconverter for = " + typeConverter);

				return BsonType.EndOfDocument;
			}

			if (type.Equals(typeof(Int32Converter)))
			{				
				return BsonType.Int32;
			}

			if (type.Equals(typeof(BooleanConverter)))
			{
				return BsonType.Boolean;
			}

			if (type.Equals(typeof(DateTimeConverter)))
			{
				return BsonType.DateTime;
			}

			if (type.Equals(typeof(DoubleConverter)))
			{
				return BsonType.Double;
			}

			if (type.Equals(typeof(Int64Converter)))
			{
				return BsonType.Int64;
			}

			if (type.Equals(typeof(StringConverter)))
			{
				return BsonType.String;
			}

			if (type.Equals(typeof(TimeSpanConverter))) // TODO: ??? should be an utc datetime?
			{
				return BsonType.Timestamp;
			}

			return BsonType.EndOfDocument; // Not supported bson type conversion.			
		}

		#endregion // TypeConverter Mapping

	}
}
